﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Pipes;
using System.IO;
using System.Diagnostics;
using System.Threading;
using System.Windows;

namespace dmm
{
    class PipeRecordController : RecorderObserver
    {
        private NamedPipeServerStream pipe = null;
        /*private StreamWriter writer = null;
        private StreamReader reader = null;*/
        private Recorder recorder;
        //the output queue
        //private List<string> out_bufs = new List<string>();
        private string stat_str = "";
        public bool run = true;
        public bool exit = false;

        //private IAsyncResult aysn_result = null;
        //private IAsyncResult read_result = null;
        //private IAsyncResult write_result = null;

        ManualResetEvent ev = new ManualResetEvent(false);

        public byte[] in_buf = new byte[256];

        public PipeRecordController(Recorder recorder)
        {
            this.recorder = recorder;
            recorder.register_observer(this);

        }

        ~PipeRecordController()
        {
            recorder.unregister_observer(this);
        }


        public void onRecordStart()
        {
        }

        public void onRecordEnd()
        {

        }


        public void onRecordProgress(int frame, int sample)
        {
            //report(String.Format("SSTAT {0} {1}", (recorder != null && recorder.IsRrcording )? 1 : 0, frame));
        }


        public void onRecordError(int err, string errtext)
        {
        }


        public void start()
        {
            this.run = false;
            Debug.Write("PipeRecordController:start\n");
            pipe = new NamedPipeServerStream(@"dmm_control", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);

            Thread th = new Thread(new ParameterizedThreadStart(delegate(object obj)
            {
                this.listen(obj);
            }));
            th.Start(this);
        }

        public void OnReadComplete(IAsyncResult iAR)
        {
            //Debug.Write("\nreaded\n");
            try
            {
                int sz = pipe.EndRead(iAR);
                string response = process_cmd(sz);
                if(response != String.Empty)
                 pipe.BeginWrite(Encoding.ASCII.GetBytes(response), 0, response.Length, new AsyncCallback(this.OnWriteComplete), this);
            }
            catch (Exception e)
            {
                Debug.Write(e);
                ev.Set();
            }

        }

        public void OnWriteComplete(IAsyncResult iAR)
        {
            //Debug.Write("\nwrited\n");                  
            pipe.EndWrite(iAR);
            ev.Set();
        }

        public string process_cmd(int sz)
        {
            if (sz != 0)
            {
                string msg = System.Text.Encoding.ASCII.GetString(in_buf,0,sz);
                Debug.Write(String.Format("\nreceive cmd:{0}\n", msg));
                //msg = msg.Substring(0, sz);

                string cmd = msg.Substring(0, 5);
                if (cmd == "CRECO")
                {
                    string str = msg.Substring(6);
                    var parts = str.Split(' ');
                    int left = int.Parse(parts[0]);
                    int top = int.Parse(parts[1]);
                    int width = int.Parse(parts[2]);
                    int height = int.Parse(parts[3]);

                    //theWindow.Dispatcher.Invoke((Action)(()=>{ theWindow.capture_current_window(left, top, width, height);}));
                    recorder.capture_current_win_rect(left, top, width, height);
                    return "SRECO 1";
                }
                else if (cmd == "CSTAT")
                {
                    return "SSTAT " + (((recorder!=null) && recorder.IsRrcording) ? "1" : "0");
                }
                else if (cmd == "CSTOP")
                {
                    recorder.stop();
                    return "SSTOP 1";
                }
            }
            return String.Empty;
        }

        public void listen(object obj)
        {


            PipeRecordController self = obj as PipeRecordController;

            using (pipe)
            {   
                try
                {
                    pipe.WaitForConnection();
                    this.run = true;
                    ev.Reset();
                    while (pipe.IsConnected)
                    {
                        //IAsyncResult iAR = pipe.BeginRead(in_buf, 0, 256, new AsyncCallback(this.OnReadComplete), this);
                        
                            IAsyncResult iAR = pipe.BeginRead(in_buf, 0, 256, null, this);
                            iAR.AsyncWaitHandle.WaitOne();
                            int sz = pipe.EndRead(iAR);

                            string res = process_cmd(sz);
                            //Debug.Assert(res != String.Empty);
                            if (res != String.Empty)
                            {
                                iAR = pipe.BeginWrite(Encoding.ASCII.GetBytes(res), 0, res.Length, null, this);
                                iAR.AsyncWaitHandle.WaitOne();
                                pipe.EndWrite(iAR);
                            }
                        
                    }
                    this.run = false;
                }
                catch (Exception e)
                {
                    Debug.Write(e);
                }
                finally
                {
                    pipe.Close();
                }
            }

            //start a new thread
            Debug.Write("PipeRecordController:new Thread\n");
            if (!self.exit) self.start();

        }


        public void close()
        {
            exit = true;
           /* if (run)
                ev.Set();
            else*/
                pipe.Dispose();

        }

        public void report(string msg)
        {
            stat_str = msg;
        }

    }
}
